home *** CD-ROM | disk | FTP | other *** search
- Now What?
- OSS Personal Pascal and the beginner - part 2
- written by David Meile
-
- [Copyright 1986 David Meile, all rights reserved. Permission is
- given to Atari user groups to reprint this article, as long as
- this statement is included. OSS Personal Pascal is a product of
- Optimized Systems Software, Inc. I am not related to the company,
- I simply bought their compiler.]
-
- Windows, Graphics and Pascal
-
- One of the many nice things about OSS Personal Pascal is that it
- provides the Pascal programmer with simple access to many of the GEM
- operating system features. Unfortunately, while access is simple,
- it is not always EASY. GEM requires a lot of prompting before it will
- produce something like a Window. But, once you get the basic idea
- of how to access GEM from Pascal, it DOES become easier as you write
- more programs.
-
- Last time, I said I was going to draw some lines. Actually, I am
- going to do a little more than that ... I am going to introduce the
- basics of creating a Window to draw ON. The program that follows is
- called GRAPHICS.PAS.
-
- The program
-
- PROGRAM graphics;
-
- { Clear the screen and draw something }
-
- CONST
- {$I gemconst.pas }
-
- TYPE
- {$I gemtype.pas }
-
- VAR
- x,y,w,h,
- my_window : integer;
- my_event : integer;
- wind_type : integer;
- title : Window_Title;
-
- { The following must be defined for completeness, but are not used }
-
- message : Message_Buffer;
- key : integer;
- bcnt,bstate : integer;
- mx,my : integer;
- kbd_state : integer;
-
- {$I gemsubs.pas }
-
- PROCEDURE Do_Graph;
-
- BEGIN
- wind_type := G_Name;
- title := ' Drawing a box ';
- my_window := New_Window( wind_type, title, 0, 0, 0, 0 );
- Hide_Mouse;
- Open_Window( my_window, 0, 0, 0, 0 );
- Set_Window( my_window );
- Work_Rect( my_window, x, y, w, h );
- Set_Clip( x, y, w, h );
- Paint_Color( White );
- Paint_Rect( 0, 0, w, h );
- Line_Color( Black );
- Text_Color( Black );
- Draw_String( 10,10, 'You can draw text on screen too!');
- Line( 15,15, 15,100 );
- Line_To( 100,100 );
- Line_To( 100,15 );
- Line_To( 15,15 );
- Line_To( 100,100 );
- Line( 15,100, 100,15 );
- Draw_String( 15,110, 'Click the left button to exit...');
- my_event := Get_Event( E_Button, 1, 1, 1, 0,
- False, 0, 0, 0, 0,
- False, 0, 0, 0, 0,
- message, key, bcnt, bstate, mx, my, kbd_state );
- Close_Window( my_window );
- Show_Mouse;
- Delete_Window( my_window );
- END;
-
- BEGIN
- IF Init_Gem >= 0 THEN
- BEGIN
- Do_Graph;
- Exit_Gem;
- END;
- END.
-
- And now ... the explanation
-
- Quite a lot of things are going on in that little program, right?
- I am sure that you recognize most of the lines at the very end. There
- is the 'Init_Gem' function, asking GEM if it can create a new workspace.
- There is the 'Exit_Gem' procedure, telling GEM that the program is
- finished with the workspace. And there is that funny line that simply
- says 'Do_Graph'.
-
- But first, a brief digression
-
- Pascal works best in small chunks of code, called PROCEDURES and
- FUNCTIONS. As you may remember, a function is a subprogram that, when
- called, returns a single value. The function 'Init_Gem' returns an
- integer value greater or equal to zero when GEM can run the program.
-
- A PROCEDURE is a subprogram that, when called, performs some sort
- of action. It may (or may not) return one or more values. Procedures
- can require PARAMETERS, which are variables with some sort of value.
- 'Draw_String' is a procedure in the program above. It's parameters
- are two integer values and a string. (Remember, strings are enclosed
- by single quota marks - 'This is a string'). 'Exit_Gem' is a procedure
- with no parameters.
-
- One of the advantages of Pascal over BASIC is that procedures and
- functions can have variables that do not affect the program outside
- of that particular subprogram. A short example:
-
- Program example1;
-
- VAR
- a, b : integer;
-
- Procedure dark( x : integer; y : integer );
-
- VAR
- a, b : integer;
-
- BEGIN {Procedure dark}
- a := x;
- b := a * y;
- Writeln( 'a = ', a , ' b = ', b );
- END; {dark}
-
- BEGIN {Main program example1}
- a := 10;
- b := 5;
- dark( a, b );
- Writeln( 'a = ', a, ' b = ', b );
- END. {example 1}
-
- What do you think this short program will do? Print out values
- of 'a' and 'b' of course. First, assign 10 to a and 5 to b. Then
- call the procedure dark. The two parameters are a and b ... they are
- called x and y WITHIN procedure dark. Assign x to a (so a = 10) and
- assign a * y to b (10 * 5 = 50, so b = 50). The Writeln will print
- out the following:
-
- a = 10 b = 50
-
- Now, exit dark and go back to the main program. Here we print out
- the values of a and b. But the values of a and b have not changed
- in the main program, they only changed within procedure dark. So,
- a is STILL 10 and b is STILL 5 in the main program. The Writeln will
- print out the following:
-
- a = 10 b = 5
-
- If you have followed this, congratulations! You now know about LOCAL
- (within a procedure) variables.
-
- Now, back to the REAL program
-
- OK. You can see that 'Do_Graph' is a procedure. There are no
- parameters, so any variables included in Do_Graph must be GLOBAL ..
- that is, the variables listed at the top of the program apply to the
- procedure as well. A GLOBAL variable can be changed by ANY subprogram,
- and should not be used much within your own programs. 'Proper' Pascal
- programs almost always use LOCAL variables within procedures, passing
- parameters back to the main program when necessary.
-
- With that in mind, let's look at what's going on in the procedure
- called Do_Graph. The first thing you can see are several assignments.
- 'wind_type' is an integer variable used in the function New_Window.
- It can be made up of several parts, and describes the parts of the
- GEM Window we want to be there. These include the scroll bars, the
- "close window" box, and the window name. G_Name is an bit value
- for the window name. G_Close is another bit value for the close
- window box. When combined they produce an integer value that we can
- assign to wind_type. To include both, you would type:
-
- wind_type := G_Name | G_Close;
-
- Additional parts of a GEM window can be included: G_Full, G_Move,
- G_Info, etc.
-
- Since I'm going to have a window name, I may as well tell GEM what
- it is, right? That is the variable 'title'. You'll notice that the
- variable is declared 'title : Window_Title'. Window_Title is a special
- TYPE included in the GEMTYPE.PAS file. If you're interested, you can
- look at GEMTYPE.PAS to see how "special" types are declared.
-
- Having my two variables assigned, I make a call to the function
- called 'New_Window'. You can tell it is a function because it's on the
- right side of an assignment statement. The variable 'my_window' is
- an integer, so the function New_Window returns an integer value. The
- function New_Window asks GEM to set up space for a window, and lets
- Pascal know how to access it by number. It also tells GEM what the
- title for the window should be.
-
- I don't want the mouse arrow to clutter up my nice graphics screen,
- so I tell GEM to hide it with the procedure 'Hide_Mouse'. You MUST
- include a 'Show_Mouse' somewhere in your program for every Hide_Mouse
- you execute. If you don't, when your program is finished, GEM will
- still be hiding the mouse when you get back to the Desktop ... not
- a pretty 'sight'!
-
- OK. The mouse is in hiding, and I can safely OPEN a new window,
- using the procedure 'Open_Window' (of course). I tell GEM to open
- the window it has reserved and to give me the maximum amount of space
- to work with (the 0,0,0,0 tells GEM to make the window as BIG as possible,
- which generally means full-screen. Don't exceed the values that you used
- in the New_Window function call...). To make SURE that the window I
- just opened is the one I will be using, I use the procedure 'Set_Window'.
- If you have several windows open at once, you use Set_Window to tell
- GEM which one you're going to be working with now. Notice that the
- variable 'my_window' lets GEM know WHICH window I'm talking about.
-
- The window is open and set. I want to find out how much space I
- have to work with, so I use the procedure 'Work_Rect'. The variables
- x,y,w, and h are given values by the procedure Work_Rect, and I can
- use them in my program to determine several things. The x and y tell
- me where the 'origin' of the window is, and w and h tell me how wide
- and high the window is. This is useful information -- it means I don't
- have to write separate procedures for each resolution mode (LOW, MEDIUM
- and HIGH resolution). Instead, I can restrict myself to the boundaries
- given by these values.
-
- I can do better than that. I can tell GEM to ignore things I draw
- that are outside the window boundaries by making a call to 'Set_Clip'.
- This procedure will take the values I got from Work_Rect and tell GEM
- not to do any actual drawing outside of those boundaries. Now, regardless
- of how big or small my window is, I can draw on it without fear of
- crashing the system by going outside of the window boundaries.
-
- I have my window on screen, but it's got the background color of
- the GEM Desktop. I much prefer to draw on a white background, so I
- set the 'Paint_Color' to white and then tell GEM to paint the entire
- window that color using 'Paint_Rect'. Notice that the width and height
- are passed to Paint_Rect. I have set the origin at 0,0, which is the
- upper left corner of the window (or it's supposed to be ... try it
- using x,y instead of 0,0 and note the results).
-
- OK, I have a white background, so I'm going to draw things with
- black lines. I set 'Line_Color' and 'Text_Color' to black. Then I
- call procedure 'Draw_String'. The two parameters are x and y pixel
- values, x going horizontally and y going vertically. 10,10 is 10 pixels
- to the right and 10 pixels down.
-
- Next, I draw some lines. Ideally, I would be drawing a square,
- with corners at 15,15 and 100,100. However, it may not look like it
- on your screen. The reason for this is that there are MORE x pixels
- than there are y pixels on your screen. In LOW resolution there are
- 320 x 200 pixels. In HIGH resolution there are 640 x 400 pixels.
- In MEDIUM resolution there are 640 x 200 pixels. The first number
- is the x pixel value, the second number is the y pixel value.
-
- For now, we'll not worry about it. BUT, if you're going to be doing
- lots of graphics, you'll want to set up some sort of "fudge-factor" to
- make things look right. One possible solution is to multiply the x
- value by some constant based on the resolution mode you are in. For
- example, in MEDIUM resolution, multiplying x by 3.2 would compensate.
- (3.2 x 200 = 640.)
-
- There are two procedures for drawing lines: 'Line' and 'Line_To'.
- The first requires two endpoints, the beginning of the line and the
- end of the line. The second requires one endpoint, using the end of
- the last line as the beginning of the new line.
-
- My lines are drawn, and all of the text is also drawn. The second
- Draw_String is an absolute MUST. The reason? You should ALWAYS let
- the person using your program know what to do next! If the second
- line were omitted, I would have no idea that I was supposed to press
- the left mouse button to exit the program. It is good programming
- practice to include such 'hints' where they are needed.
-
- How do I tell when the left button is pressed? I use the Pascal
- function 'Get_Event'. There are a LOT of parameters for this function.
- Some are not needed just to test for a simple click on the left mouse
- button. These are duly noted in the VAR declaration part of the program.
- 'my_event' is an integer value returned by Get_Event. In many cases,
- your program would take this value and continue to do something else.
- Here, it simply sets up the program to await a click of the 'ol mouse
- button.
-
- Get_Event parameters needed to test the mouse button include
- E_Button ("I'm waiting for a mouse button event..."), and several values
- that follow. The first '1' means "left mouse button", the second '1'
- means "waiting for user to click button", the third '1' means "wait for
- one click" and the '0' means "wait this long for the button click". In
- this case, that '0' is meaningless (as are the 'False' and other '0's in
- the parameter list) since we are not using the E_Timer event flag.
- Everything else is simply there for completeness.
-
- Once I click the mouse, I close the window I created with
- 'Close_Window'. Then I 'Show_Mouse', because I hid it earlier and
- I want to SEE the mouse arrow once my program is finished! Then I
- 'Delete_Window', which releases the space GEM has allocated for my
- window since I no longer need it.
-
- Done at last. Look at all of that work, simply to draw a couple of
- lines on the screen! However, the next time I want to create a window
- and draw some lines, it'll be that much easier...
-
- Of RAM disks and Pascal programming
-
- If you have a 1040 ST, or a 520 ST with a 1 megabyte memory upgrade,
- you can move the OSS Personal Pascal files from disk to a RAM disk.
- This makes things like calling the compiler and linker MUCH faster.
- You need to make sure that the RAM disk you are using can survive a
- computer RESET. Talk to your local Atari ST user group to see if they
- have a copy of one of the many RAM disks available. One such is called
- ETERNAL.PRG, another is available in an archive file called YARD.ARC.
-
- To automate moving your Pascal program files to the RAM disk, you
- need to look for a program such as FLDR2DSK.PRG, also available from many
- bulletin boards and user groups. I use this program, but do not put it
- into the AUTO folder as the instructions mention. The reason is that
- my RAM disk is created on a number of disks, and there is no real reason
- to reboot my system simply to load OSS Personal Pascal.
-
- If you own an Atari 520 ST without the memory upgrade, you can speed
- things up somewhat by using a RAM disk and putting your programs on the
- RAM disk instead of Pascal. There are some instructions available to do
- this, which should be available from your local user group. If you can't
- find them, I will be happy to copy them for the cost of a STAMPED self-
- addressed envelope. About the best you can hope for is a 200k RAM disk.
-
-
- Wrapping things up
-
- I'd like to thank everybody who sent me letters and E-Mail regarding
- the first column. In future months, you can expect to see some more
- articles on working with OSS Personal Pascal.
-
- In next month's article, I will discuss reading from and saving to
- files. I'll also talk about using the pre-defined DIALOG boxes that
- are accessible from OSS Personal Pascal.
-
- I'm open to answering some SIMPLE questions regarding
- Personal Pascal. You can reach me via GEnie as D.MEILE, or
- write (include a stamp, please) to:
-
- David Meile
- Box 13038 - Dinkytown Station
- Minneapolis, MN 55414
-
- Additional reading
-
- If you are interested in a college text for Pascal, you might find
- that AN INTRODUCTION TO PROGRAMMING AND PROBLEM SOLVING WITH PASCAL by
- G. Michael Schneider, Steven W. Weingart and David M. Perlman is useful.
- It is published by John Wiley and Sons, and the latest version was
- published in (I believe) 1984. It was the text used for beginning
- programming classes at the University of Minnesota in Minneapolis when
- I learned to program in Pascal.
-